#include <iostream>
#include <string>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <memory>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unordered_map>
#include <signal.h>
#include "SingletonThreadPool.hpp"
#include "log.hpp"
#include "Task.hpp"

enum
{
	SOCKETERR = 1,
	BINDERR,
	LISTENERR
};

const std::string defaultip = "0.0.0.0";
const uint16_t defaultport = 8080;

class TcpServer;

struct ThreadData
{
	ThreadData(int sockfd, const uint16_t &clientport, const std::string &clientip, TcpServer *tver)
	: _sockfd(sockfd), _clientport(clientport), _clientip(clientip) ,_tver(tver) 
	{}

	int _sockfd;
	uint16_t _clientport;
	std::string _clientip;
	TcpServer* _tver;
};

class TcpServer
{

public:
	TcpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip) : _ip(ip), _port(port), _running(false)
	{}

	void tverinit()
	{
		// std::cout << "init" << std::endl;
		_listensockfd = socket(AF_INET, SOCK_STREAM, 0);
		if (_listensockfd < 0)
		{
			lg(FATAL, "listensocket create fail, sockfd: %d, errno: %d, strerror: %s\n", _listensockfd, errno, strerror(errno));
			exit(SOCKETERR);
		}
		lg(INFO, "listensocket create success, sockfd: %d, errno: %d, strerror: %s\n", _listensockfd, errno, strerror(errno));

		struct sockaddr_in local;
		// bzero(&local, sizeof(local));
		memset(&local, 0, sizeof(local));
		local.sin_family = AF_INET;
		local.sin_port = htons(_port);

		local.sin_addr.s_addr = INADDR_ANY;
		// local.sin_addr.s_addr = inet_addr(_ip.c_str());

		socklen_t len = sizeof(local);
		// bind
		if (bind(_listensockfd, (struct sockaddr *)&local, len) < 0)
		{
			lg(FATAL, "listensockfd bind fail, listensockfd: %d, errno: %d, strerror: %s\n", _listensockfd, errno, strerror(errno));
			exit(BINDERR);
		}
		lg(INFO, "listensockfd bind success, listensockfd: %d, errno: %d, strerror: %s\n", _listensockfd, errno, strerror(errno));

		// 将套接字修改为监听状态
		if (listen(_listensockfd, 5) < 0)
		{
			lg(FATAL, "listen fail, errno: %d, strerror: %s\n", errno, strerror(errno));
			exit(LISTENERR);
		}
		lg(INFO, "listen success, errno: %d, strerror: %s\n", errno, strerror(errno));
	}

	// static void *Routine(void* args)
	// {
	// 	pthread_detach(pthread_self());
	// 	ThreadData* td = static_cast<ThreadData*>(args);
	// 	std::cout << "线程启动成功" << td->_sockfd << std::endl;
	// 	td->_tver->Service(td->_sockfd, td->_clientip, td->_clientport);
	// 	// close(td->_sockfd);
	// 	delete td;

	// 	return nullptr;
	// }

	void start()
	{
		// std::cout << "threadpool start" << std::endl;
		SingletonThreadPool<Task>::GetInStance()->ThreadStart();

		signal(SIGCHLD, SIG_IGN);
		// _running = true;
		for (;;)
		{
			struct sockaddr_in client;
			socklen_t len = sizeof(client);
			//获取新链接, 失败不影响获取下一个
			int sockfd = accept(_listensockfd, (struct sockaddr *)&client, &len);
			if (sockfd < 0)
			{
				lg(WARNING, "_sockfd create fail, sockfd: %d, errno: %d, strerror: %s\n", sockfd, errno, strerror(errno));
				continue;
			}
			uint16_t clientport = ntohs(client.sin_port);
			char clientip[32]; // 维护ip只需要16字节的大小，以防万一我们开辟32字节
			inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip)); //将字符串维护在clientip数组中
			lg(INFO, "create a new link ..., sockfd: %d, clientip: %s, clientport: %d\n", sockfd, clientip, clientport);

			// TCP是面向字节流的,单线程版本
			// Service(sockfd, clientip, clientport);
			// close(sockfd);

			//多进程版本 缺点：创建一个进程成本太高，进程地址空间 页表 部分物理空间
			// pid_t id = fork();
			// if(id == 0)
			// {
			// 	// std::cout << sockfd << std::endl;
			// 	//因为子进程会继承父进程的文件描述符，listensockfd和sockfd都会被子进程继承
			// 	//其中listensockfd监听描述符可关可不关，sockfd进行服务的描述符建议还是关掉
			// 	//不关的话，父进程文件描述符表的位置会越用越少
			// 	close(_listensockfd);
			// 	// if(fork() > 0) exit(0); //子进程退出，让它的父进程回收
			// 	Service(sockfd, clientip, clientport); //正真执行服务的是孙子进程
			// 	//服务结束之后关闭对应的描述符->子进程
			// 	close(sockfd);
			// 	exit(0);
			// } 
			//服务完之后，父进程也关闭对应的描述符，不会影响其他进程
			// close(sockfd); //打印的是父进程的文件描述符，关闭的话会一直用一个位置
			// pid_t rid = waitpid(id, nullptr, 0);
			//由于g++编译器比较严格，对rid变量进行使用
			// (void)rid;


			//多线程版本 缺点：长服务，客户端不退，线程一直存在，峰期可能会创建大量线程导致服务器压力过大
			//线程所在进程中获取的文件描述符是与进程共享的没有多的
			// ThreadData* td = new ThreadData(sockfd, clientport, clientip, this);
			// std::unique_ptr<ThreadData> td(new ThreadData(sockfd, clientport, clientip, this)); 不能使用智能指针

			// ThreadData* td = new ThreadData(sockfd, clientport, clientip, this); 

			//不要使用join进行线程等待，会造成主进程卡住，不会往后继续进行了
			// pthread_t tid;
			// pthread_create(&tid, nullptr, Routine, &td); 错误原因: 使用智能指针传入的是智能指针的地址，并不是我们new出来的地址，我们new出来的地址被封装在了智能指针内部
			// pthread_create(&tid, nullptr, Routine, td);

			//线程池版本
			Task t(sockfd, clientport, clientip);
			SingletonThreadPool<Task>::GetInStance()->push(t);
		}
	}

	// void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)
	// {
	// 	char buffer[4096];

	// 	while (true)
	// 	{
	// 		// std::cout << "开始接收消息"<< std::endl;
	// 		ssize_t n = read(sockfd, buffer, sizeof(buffer));
	// 		if (n > 0)
	// 		{
	// 			buffer[n] = {0};
	// 			std::cout << "client say@ ";
	// 			std::string message = buffer;
	// 			std::cout << message << std::endl;
	// 			write(sockfd, message.c_str(), sizeof(message));
	// 		}
	// 		else if (n == 0)
	// 		{
	// 			lg(INFO, "Did not get it! [sockfd: %d, clientip: %s : clientport: %d] quit...\n", sockfd, clientip, clientport);
	// 			break;
	// 		}
	// 		else
	// 		{
	// 			lg(WARNING, "Did not get it! [sockfd: %d, clientip: %s : clientport: %d] quit...\n", sockfd, clientip, clientport);
	// 			break;
	// 		}
	// 	}
	// }

	~TcpServer(){};
private:
	int _listensockfd;
	uint16_t _port;
	std::string _ip;
	bool _running;
};
